﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using VM.Core;
using VM.PlatformSDKCS;
using VMControls.Interface;
using VMControls.RenderInterface;
using VMControls.Winform.Release;
using Mvvm.Commands;
using GlobalCameraModuleCs;
using ImageSourceModuleCs;
using IMVSCircleFindModuCs;
using IMVSLineFindModuCs;
using IMVSCaliperCornerModuCs;
using IMVSFastFeatureMatchModuCs;
using IMVSHPFeatureMatchModuCs;
using VisionDesigner;
using VisionDesigner.FastFeaturePatMatch;

using VisionDesigner;
using VisionDesigner.FastFeaturePatMatch;
using MvdXmlParse;

using Vision.src;
using Vision.roi;
using Vision.page;
using System.Diagnostics;

namespace Vision.page
{
    public partial class FastFeaturePatMatchControl : UserControl
    {

        private string ModuleName = "";

        private string[] modelExportPathList = new string[1]; // 本示例只有一个模型文件，所以数组长度设为1

        /// <summary>
        /// 训练图像
        /// </summary>
        private CMvdImage _TrainImage = null;


        IMVSHPFeatureMatchModuTool iMVSHPFeatureMatchModuTool;

        private List<IROI> TemplateROU = new List<IROI>(); // 多ROI List

        /// <summary>
        /// 计时器
        /// </summary>
        private Stopwatch _StopWatch = new Stopwatch();

        /// <summary>
        /// ROI
        /// </summary>
        private CMvdShape _ROIShape = null;

        /// <summary>
        /// 掩膜图形列表
        /// </summary>
        private List<CMvdShape> _MaskShapeList = new List<CMvdShape>();

        /// <summary>
        /// 匹配框列表
        /// </summary>
        private List<CMvdRectangleF> _MatchBoxList = new List<CMvdRectangleF>();

        /// <summary>
        /// 匹配轮廓列表
        /// </summary>
        private List<CMvdPointSetF> _MatchOutlineList = new List<CMvdPointSetF>();

        /// <summary>
        /// 快速模板算子
        /// </summary>
        private CFastFeaturePattern _FastFeaturePattern = null;

        /// <summary>
        /// 模型
        /// </summary>
        internal CFastFeaturePattern FastFeaturePattern { get; set; }

        /// <summary>
        /// 快速匹配Tool算子
        /// </summary>
        private CFastFeaturePatMatchTool _FastFeaturePatMatchTool = null;

        /// <summary>
        /// 绘制Region区域
        /// </summary>
        private List<CPatMatchRegion> _DrawRegionList = new List<CPatMatchRegion>();

        /// <summary>
        /// 基准点
        /// </summary>
        private CMvdPointSetF _DrawFixPoint = new CMvdPointSetF();


        public FastFeaturePatMatchControl()
        {
            InitializeComponent();
        }

        public FastFeaturePatMatchControl(string FeatureModuleName)
        {
            InitializeComponent();
            this.ModuleName = FeatureModuleName;


        }

        private void button1_Click(object sender, EventArgs e)
        {
            
        }

        private void button2_Click(object sender, EventArgs e)
        {
            
        }

        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                if (button3.Text == "开启建模")
                {
                    Form1.MyForm.mvdRenderActivex1.MVDShapeChangedEvent -= new VisionDesigner.MVDRenderActivex.MVDShapesChangedEventHandler(this.MvdRenderActivex1_MVDShapeChangedEvent); 
                    Form1.MyForm.mvdRenderActivex1.MVDShapeChangedEvent += new VisionDesigner.MVDRenderActivex.MVDShapesChangedEventHandler(this.MvdRenderActivex1_MVDShapeChangedEvent); 
                    
                    button3.Text = "关闭建模";
                }
                else if (button3.Text == "关闭建模")
                {
                    Form1.MyForm.mvdRenderActivex1.MVDShapeChangedEvent -= new VisionDesigner.MVDRenderActivex.MVDShapesChangedEventHandler(this.MvdRenderActivex1_MVDShapeChangedEvent); 
                    button3.Text = "开启建模";
                }
            }
            catch (VmException ex)
            {
                string strMsg = "ErrorMessage is " + ex.errorMessage + " ErrorCode is " + Convert.ToString(ex.errorCode, 16);
            }
            catch (Exception ex)
            {
                string strMsg = Convert.ToString(ex);
            }
        }

        internal void MvdRenderActivex1_MVDShapeChangedEvent(MVDRenderActivex.MVD_SHAPE_EVENT_TYPE enEventType, MVD_SHAPE_TYPE enShapeType, CMvdShape cShapeObj)
        {
            if (MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_SELECTED == enEventType)
            {
                return;
            }
            if (MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_EDITED == enEventType)
            {
                return;
            }


            // 图形删除事件
            if (MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_DELETED == enEventType)
            {
                // 删除Region
                foreach (var item in _DrawRegionList)
                {
                    if (cShapeObj == item.Shape)
                    {
                        _DrawRegionList.Remove(item);
                        break;
                    }
                }

                if (cShapeObj == _DrawFixPoint)
                {
                    _DrawFixPoint = null;
                }
                return;
            }


            if (this.radioButtonRoiAll.Checked)
            {
                MessageBox.Show("Shapes are not allowed to be added in the AllRegion Mode\r\n");
                Form1.MyForm.mvdRenderActivex1.DeleteShape(cShapeObj);
                Form1.MyForm.mvdRenderActivex1.Display();
                return;
            }


            // 图形增加事件
            bool bAddToDrawList = false;
            if (MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_ADDED == enEventType)
            {
                var region = new CPatMatchRegion();
                switch (cShapeObj.ShapeType)
                {
                    case MVD_SHAPE_TYPE.MvdShapeRectangle:
                        {
                            region.Shape = cShapeObj as CMvdRectangleF;
                        }
                        break;
                    case MVD_SHAPE_TYPE.MvdShapeAnnularSector:
                        {
                            region.Shape = cShapeObj as CMvdAnnularSectorF;
                        }
                        break;
                    case MVD_SHAPE_TYPE.MvdShapePolygon:
                        {
                            region.Shape = cShapeObj as CMvdPolygonF;
                        }
                        break;
                    default:
                        {
                            MessageBox.Show("The shape is not supported.\r\n");
                            break;
                        }
                }

                if (((this.radioButtonRoiRect.Checked) && (MVD_SHAPE_TYPE.MvdShapeRectangle == enShapeType))
                 || ((this.radioButtonRoiAnnulus.Checked) && (MVD_SHAPE_TYPE.MvdShapeAnnularSector == enShapeType))
                 || ((this.radioButtonRoiPolygon.Checked) && (MVD_SHAPE_TYPE.MvdShapePolygon == enShapeType)))
                {
                    region.Sign = true;
                    _DrawRegionList.Add(region);
                    bAddToDrawList = true;
                }

                if (((this.radioButtonMaskRect.Checked) && (MVD_SHAPE_TYPE.MvdShapeRectangle == enShapeType))
                 || ((this.radioButtonMaskAnnulus.Checked) && (MVD_SHAPE_TYPE.MvdShapeAnnularSector == enShapeType))
                 || ((this.radioButtonMaskPolygon.Checked) && (MVD_SHAPE_TYPE.MvdShapePolygon == enShapeType)))
                {
                    region.Sign = false;
                    _DrawRegionList.Add(region);
                    bAddToDrawList = true;
                }

                if (!bAddToDrawList)
                {
                    MessageBox.Show("The shape that is inconsistent with the checked type will be deleted.\r\n");
                    Form1.MyForm.mvdRenderActivex1.DeleteShape(cShapeObj);
                    Form1.MyForm.mvdRenderActivex1.Display();
                }

                this.training();

                return;
            }

            MessageBox.Show("The shape that is inconsistent with the checked type will be deleted.\r\n");
            Form1.MyForm.mvdRenderActivex1.DeleteShape(cShapeObj);
            Form1.MyForm.mvdRenderActivex1.Display();

        }

        private void training()
        {
            try
            {
                if ((null == FastFeaturePattern) || (null == FastFeaturePattern.InputImage))
                {
                    throw new MvdException(MVD_MODULE_TYPE.MVD_MODUL_APP, MVD_ERROR_CODE.MVD_E_CALLORDER);
                }

                // region更新
                FastFeaturePattern.RegionList.Clear();
                foreach (var item in _DrawRegionList)
                {
                    var region = new CPatMatchRegion();
                    switch (item.Shape.ShapeType)
                    {
                        case MVD_SHAPE_TYPE.MvdShapeRectangle:
                            {
                                var regionShape = item.Shape as CMvdRectangleF;
                                regionShape.Interaction = true;
                                region.Shape = regionShape.Clone() as CMvdRectangleF;
                            }
                            break;
                        case MVD_SHAPE_TYPE.MvdShapeAnnularSector:
                            {
                                var regionShape = item.Shape as CMvdAnnularSectorF;
                                regionShape.Interaction = true;
                                region.Shape = regionShape.Clone() as CMvdAnnularSectorF;
                            }
                            break;
                        case MVD_SHAPE_TYPE.MvdShapePolygon:
                            {
                                var regionShape = item.Shape as CMvdPolygonF;
                                regionShape.Interaction = true;
                                region.Shape = regionShape.Clone() as CMvdPolygonF;
                            }
                            break;
                        default:
                            {
                                throw new MvdException(MVD_MODULE_TYPE.MVD_MODUL_APP, MVD_ERROR_CODE.MVD_E_PARAMETER_ILLEGAL);
                            }
                    }
                    region.Sign = item.Sign;

                    FastFeaturePattern.RegionList.Add(region);
                }

                _StopWatch.Restart();
                FastFeaturePattern.Train();
                _StopWatch.Stop();
                Form1.MyForm.SetLabelText("Train Pattern Success! \r\n");
                Form1.MyForm.SetLabelText("Running cost: " + _StopWatch.ElapsedMilliseconds.ToString("#0.000") + " ms.\r\n");

                Form1.MyForm.mvdRenderActivex1.ClearImages();
                Form1.MyForm.mvdRenderActivex1.Display(MVDRenderActivex.MVD_REFRESH_MODE.Sync);


                Form1.MyForm.mvdRenderActivex1.LoadImageFromObject(FastFeaturePattern.Result.Data.TrainedImage);
                Form1.MyForm.mvdRenderActivex1.Display(MVDRenderActivex.MVD_REFRESH_MODE.Sync);


                if (null != FastFeaturePattern.Result.OutlineList)
                {
                    foreach (var item in FastFeaturePattern.Result.OutlineList)
                    {
                        CMvdPointSetF pointSetG = new CMvdPointSetF();
                        CMvdPointSetF pointSetY = new CMvdPointSetF();
                        CMvdPointSetF pointSetR = new CMvdPointSetF();

                        foreach (var point in item.EdgePointList)
                        {
                            if (0 == point.Score)
                            {
                                pointSetG.AddPoint(point.Position.fX, point.Position.fY);
                            }
                            else if (1 == point.Score)
                            {
                                pointSetY.AddPoint(point.Position.fX, point.Position.fY);
                            }
                            else if (2 == point.Score)
                            {
                                pointSetR.AddPoint(point.Position.fX, point.Position.fY);
                            }
                        }

                        pointSetG.BorderColor = new MVD_COLOR(0, 255, 0, 255);
                        pointSetY.BorderColor = new MVD_COLOR(255, 255, 0, 255);
                        pointSetR.BorderColor = new MVD_COLOR(255, 0, 0, 255);

                        if (0 != pointSetG.PointsList.Count)
                        {
                            Form1.MyForm.mvdRenderActivex1.AddShape(pointSetG);
                        }

                        if (0 != pointSetY.PointsList.Count)
                        {
                            Form1.MyForm.mvdRenderActivex1.AddShape(pointSetY);
                        }

                        if (0 != pointSetR.PointsList.Count)
                        {
                            Form1.MyForm.mvdRenderActivex1.AddShape(pointSetR);
                        }
                    }
                    Form1.MyForm.mvdRenderActivex1.Display();

                }

            }
            catch (MvdException ex)
            {
                Form1.MyForm.SetLabelText("An error occurred while running train. ErrorCode: 0x" + ex.ErrorCode.ToString("X") + "\r\n");
            }
            catch (System.Exception ex)
            {
                Form1.MyForm.SetLabelText("An error occurred while running train with ' " + ex.Message + " ', ex stack trace is : " + ex.StackTrace + ".\r\n");
            }
        }

        private void buttonImplement_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.OpenFileDialog fileDlg = null;
            try
            {
                fileDlg = new System.Windows.Forms.OpenFileDialog();
                //fileDlg.Filter = @"Picture|*.bmp";
                fileDlg.Filter = @"image(*.bmp;*.jpeg;*.jpg;*.png)|*.bmp;*.jpeg;*.jpg;*.png||";
                fileDlg.RestoreDirectory = true;
                if (fileDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    textBox7.Text = fileDlg.FileName;
                    if (null == _TrainImage)
                    {
                        _TrainImage = new CMvdImage();
                    }
                    _TrainImage.InitImage(fileDlg.FileName, VisionDesigner.MVD_PIXEL_FORMAT.MVD_PIXEL_MONO_08);
                    Form1.MyForm.mvdRenderActivex1.LoadImageFromObject(_TrainImage);
                    //同步刷新，避免图形显示偏移,加载掩膜图像失败
                    Form1.MyForm.mvdRenderActivex1.Display(MVDRenderActivex.MVD_REFRESH_MODE.Sync);

                    // 确保 FastFeaturePattern 已初始化
                    if (FastFeaturePattern == null)
                    {
                        FastFeaturePattern = new CFastFeaturePattern();
                    }

                    FastFeaturePattern.InputImage = _TrainImage;
                    FastFeaturePattern.MaskImage = null;
                    FastFeaturePattern.RegionList.Clear();

                    _DrawRegionList.Clear();
                    _DrawFixPoint = null;

                    if ((FastFeaturePattern.BasicParam.FixPoint.fX >= 0)
                         && (FastFeaturePattern.BasicParam.FixPoint.fY >= 0)
                         && (FastFeaturePattern.BasicParam.FixPoint.fX <= _TrainImage.Width)
                         && (FastFeaturePattern.BasicParam.FixPoint.fY <= _TrainImage.Height))
                    {
                        CreateFixPointShape(FastFeaturePattern.BasicParam.FixPoint.fX
                                          , FastFeaturePattern.BasicParam.FixPoint.fY
                                          , ref _DrawFixPoint);

                        Form1.MyForm.mvdRenderActivex1.AddShape(_DrawFixPoint);
                    }

                }
                fileDlg.Dispose();
            }
            catch (MvdException ex)
            {
                string strMsg = "ErrorCode: 0x" + ex.ErrorCode.ToString("X") + ", message is : " + ex.Message + "\r\n";
                Form1.MyForm.SetLabelText(strMsg);
            }
            catch (System.Exception ex)
            {
                string strMsg = "Fail to load image from [" + fileDlg.FileName + "]. Error: " + ex.Message + "\r\n";
                Form1.MyForm.SetLabelText(strMsg);
            }
        }


        /// <summary>
        /// 生成基准点
        /// </summary>
        /// <param name="centerX"></param>
        /// <param name="centerY"></param>
        /// <param name="fixPoint"></param>
        private void CreateFixPointShape(float centerX, float centerY, ref CMvdPointSetF fixPoint)
        {
            fixPoint = new CMvdPointSetF();

            for (int j = 0; j < 9; j++)
            {
                float fX = centerX - 4 + j;
                fixPoint.AddPoint(fX, centerY);
                float fY = centerY - 4 + j;
                fixPoint.AddPoint(centerX, fY);
            }
            fixPoint.BorderColor = new MVD_COLOR(255, 0, 0, 255);
        }

        private void btnExportXml_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.SaveFileDialog fileDlg = null;
            FileStream fileStr = null;
            try
            {
                fileDlg = new System.Windows.Forms.SaveFileDialog();
                fileDlg.Filter = @"XMl Files(*.xml)|*.xml";
                fileDlg.RestoreDirectory = true;
                if (fileDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    byte[] fileBytes = new byte[256];
                    uint nConfigDataSize = 256;
                    uint nConfigDataLen = 0;
                    try
                    {
                        FastFeaturePattern.SaveConfiguration(fileBytes, nConfigDataSize, ref nConfigDataLen);
                    }
                    catch (MvdException ex)
                    {
                        if (MVD_ERROR_CODE.MVD_E_NOENOUGH_BUF == ex.ErrorCode)
                        {
                            fileBytes = new byte[nConfigDataLen];
                            nConfigDataSize = nConfigDataLen;
                            FastFeaturePattern.SaveConfiguration(fileBytes, nConfigDataSize, ref nConfigDataLen);
                        }
                        else
                        {
                            throw ex;
                        }
                    }

                    string filePath = fileDlg.FileName;
                    if (File.Exists(filePath))
                    {
                        File.Delete(filePath);
                    }
                    fileStr = new FileStream(filePath, FileMode.Create);
                    fileStr.Write(fileBytes, 0, Convert.ToInt32(nConfigDataLen));
                    fileStr.Flush();
                    fileStr.Close();
                    fileStr.Dispose();
                    Form1.MyForm.SetLabelText( "Finish exporting xml file.\r\n");
                }
                fileDlg.Dispose();
            }
            catch (MvdException ex)
            {
                Form1.MyForm.SetLabelText("Fail to export xml file. ErrorCode: 0x" + ex.ErrorCode.ToString("X") + "\r\n");
            }
            catch (System.Exception ex)
            {
                Form1.MyForm.SetLabelText("Fail to export xml file with error ' " + ex.Message + " '\r\n");
            }
            finally
            {
                if (null != fileDlg)
                {
                    fileDlg.Dispose();
                }
                if (null != fileStr)
                {
                    fileStr.Close();
                    fileStr.Dispose();
                }
            }

            modelExportPathList[0] = fileDlg.FileName;
            // 3.导入模板
            _FastFeaturePatMatchTool = (CFastFeaturePatMatchTool)VmSolution.Instance[this.ModuleName];
            iMVSHPFeatureMatchModuTool.ClearModelData();
            //_FastFeaturePatMatchTool.ImportModelData(modelExportPathList);    // 20221009维护版基线支持算子模型与平台模型兼容

            //// 3.导入模板
            //IMVSHPFeatureMatchModuTool iMVSHPFeatureMatchModuTool = (IMVSHPFeatureMatchModuTool)VmSolution.Instance[this.ModuleName];
            //iMVSHPFeatureMatchModuTool.ClearModelData();
            //iMVSHPFeatureMatchModuTool.ImportModelData(modelExportPathList);    // 20221009维护版基线支持算子模型与平台模型兼容
        }
    }
}
